package com.xneure.code.intf;

import java.io.File;
import java.util.Arrays;
import org.apache.commons.io.FileUtils;
import com.xneure.utils.FileUtil;
import com.xneure.utils.ObjectUtil;
import com.xneure.utils.SystemUtil;
import com.xneure.utils.bean.GUID;

public class XneureCL extends ClassLoader{
	private byte[] clsData;
	private String rootDir = SystemUtil.getTempDir() + "loadClass" + File.separator;
	private String tmpDir = rootDir + GUID.randomID().toString() + File.separator;
	private static boolean isInit = false;
	public boolean isReserve = false;

	public boolean isReserve(){
		return isReserve;
	}

	public void setReserve(boolean isReserve){
		this.isReserve = isReserve;
	}

	public Class<?> loadClass(byte[] clsData){
		try{
			if(isInit == false){
				FileUtils.deleteDirectory(new File(rootDir));
				isInit = true;
			}
			this.clsData = clsData;
			return findClass("");
		}catch(Exception e){
			return null;
		}
	}

	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException{
		if("".equals(name) == false){
			return super.findClass(name);
		}
		if(clsData == null){
			throw new ClassNotFoundException();
		}else{
			int sIndex = 0;
			int eIndex = 0;
			for(int i = 10;i < 100;i++){
				if(sIndex == 0){
					if(clsData[i] == 7 && clsData[i + 4] == 0){
						if(clsData[i + 1] == 0 && clsData[i + 3] == 1){
							if(clsData[i + 2] == 2){
								sIndex = i + 6;
							}
						}
					}
				}else{
					if(clsData[i] == 7 && clsData[i + 4] == 0){
						if(clsData[i + 1] == 0 && clsData[i + 3] == 1){
							if(clsData[i + 2] == 4){
								eIndex = i;
								break;
							}
						}
					}
				}
			}
			name = new String(Arrays.copyOfRange(clsData,sIndex,eIndex));
			name = loadClassToSystem(name);
			Class<?> defineClass = defineClass(name,clsData,0,clsData.length);
			resolveClass(defineClass);
			return defineClass;
		}
	}

	@SuppressWarnings("deprecation")
	private String loadClassToSystem(String name){
		if(isReserve){
			File f = new File(getTempDir() + name + ".class");
			File parentFile = f.getParentFile();
			if(!parentFile.exists()){
				parentFile.mkdirs();
			}
			name = name.replace("/",".");
			FileUtil.writeFile(f,clsData,false);
			try{
				ClassLoader classLoader = getClass().getClassLoader();
				ObjectUtil.callMethod(classLoader,"addURL",new File(getTempDir()).toURL());
			}catch(Exception e){
			}
		}else{
			name = name.replace("/",".");
		}
		return name;
	}

	public byte[] getClsData(){
		return clsData;
	}

	public String getTempDir(){
		return tmpDir;
	}
}
